<script setup lang="ts">
import { computed, reactive, ref } from 'vue';
import { NButton, NForm, NFormItem, NInput, NModal, NText } from 'naive-ui';

// 将字符串转换为ArrayBuffer
async function strToBuffer(str: string): Promise<ArrayBuffer> {
  const encoder = new TextEncoder();
  return encoder.encode(str).buffer;
}

// 将ArrayBuffer转换为十六进制字符串
function bufferToHex(buffer: ArrayBuffer): string {
  return Array.from(new Uint8Array(buffer))
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');
}

// 密码哈希函数：使用SHA-256哈希
async function hashPassword(password: string): Promise<string> {
  const buffer = await strToBuffer(password);
  const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
  return bufferToHex(hashBuffer);
}

// 对称加密函数：使用AES-GCM加密
async function encryptData(data: string, key: string): Promise<string> {
  try {
    // 生成密钥（将时间戳密钥转换为16字节）
    const keyBuffer = await strToBuffer(key.padStart(16, '0').substring(0, 16));
    const cryptoKey = await crypto.subtle.importKey('raw', keyBuffer, { name: 'AES-GCM' }, false, ['encrypt']);

    // 生成随机初始化向量
    const iv = crypto.getRandomValues(new Uint8Array(12));

    // 加密数据
    const dataBuffer = await strToBuffer(data);
    const encryptedBuffer = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, cryptoKey, dataBuffer);

    // 组合IV和密文并转换为十六进制
    const combined = new Uint8Array(iv.length + encryptedBuffer.byteLength);
    combined.set(iv);
    combined.set(new Uint8Array(encryptedBuffer), iv.length);

    return bufferToHex(combined.buffer);
  } catch (error) {
    // 加密失败时返回原始数据
    return data;
  }
}

// 密码加密函数：先哈希，再使用时间戳密钥加密
async function encryptPassword(password: string): Promise<string> {
  // 1. 先哈希密码
  const hashedPassword = await hashPassword(password);

  // 2. 生成时间戳密钥（时间戳整除30000）
  const timestampKey = Math.floor(Date.now() / 30000).toString();

  // 3. 使用时间戳密钥加密哈希后的密码
  const encryptedPassword = await encryptData(hashedPassword, timestampKey);

  return encryptedPassword;
}

// 定义组件属性
interface Props {
  show?: boolean;
  loading?: boolean;
}

// 定义组件事件
interface Emits {
  (e: 'update:show', value: boolean): void;
  (
    e: 'confirm',
    formData: {
      oldPassword: string;
      newPassword: string;
      confirmPassword: string;
    }
  ): void;
}

// 组件属性和事件
const props = withDefaults(defineProps<Props>(), {
  show: false,
  loading: false
});

const emit = defineEmits<Emits>();

// 表单数据
const passwordForm = reactive({
  oldPassword: '',
  newPassword: '',
  confirmPassword: ''
});

// 表单引用
const passwordFormRef = ref<InstanceType<typeof NForm>>();

// 验证规则
const passwordRules = {
  oldPassword: [{ required: true, message: '请输入旧密码', trigger: 'blur' }],
  newPassword: [
    { required: true, message: '请输入新密码', trigger: 'blur' },
    { min: 8, message: '密码长度不能少于8位', trigger: 'blur' },
    {
      validator: (_rule: any, value: string) => {
        if (!value) return new Error('请输入新密码');
        if (!/[a-zA-Z]/.test(value) || !/[0-9]/.test(value)) {
          return new Error('密码必须至少包含字母和数字');
        }
        return true;
      },
      trigger: 'blur'
    }
  ],
  confirmPassword: [
    { required: true, message: '请确认新密码', trigger: 'blur' },
    {
      validator: (_rule: any, value: string) => {
        if (!value) return new Error('请确认新密码');
        if (value !== passwordForm.newPassword) {
          return new Error('两次输入的密码不一致');
        }
        return true;
      },
      trigger: 'blur'
    }
  ]
};

// 计算密码强度
const getPasswordStrengthInfo = computed(() => {
  const password = passwordForm.newPassword;
  if (!password) {
    return { width: '0%', color: '#f0f0f0', text: '' };
  }

  let strength = 0;

  // 长度检查
  if (password.length >= 8) strength += 1;
  if (password.length >= 12) strength += 1;

  // 包含数字
  if (/\d/.test(password)) strength += 1;

  // 包含小写字母
  if (/[a-z]/.test(password)) strength += 1;

  // 包含大写字母
  if (/[A-Z]/.test(password)) strength += 1;

  // 包含特殊字符
  if (/[^a-zA-Z0-9]/.test(password)) strength += 1;

  // 归一化强度
  const normalizedStrength = Math.min(100, (strength / 6) * 100);

  if (normalizedStrength <= 33) {
    return { width: `${normalizedStrength}%`, color: '#ff4d4f', text: '弱', level: 'weak' };
  } else if (normalizedStrength <= 66) {
    return { width: `${normalizedStrength}%`, color: '#faad14', text: '中', level: 'medium' };
  }
  return { width: `${normalizedStrength}%`, color: '#52c41a', text: '强', level: 'strong' };
});

// 确认修改
const handleConfirm = async () => {
  if (!(await passwordFormRef.value?.validate())) return;

  // 使用加密函数处理密码
  const encryptedFormData = {
    oldPassword: await encryptPassword(passwordForm.oldPassword),
    newPassword: await encryptPassword(passwordForm.newPassword),
    confirmPassword: await encryptPassword(passwordForm.confirmPassword)
  };

  emit('confirm', encryptedFormData);
};

// 重置表单
const resetForm = () => {
  passwordForm.oldPassword = '';
  passwordForm.newPassword = '';
  passwordForm.confirmPassword = '';
};

// 关闭弹窗
const handleClose = () => {
  emit('update:show', false);
  setTimeout(() => {
    resetForm();
  }, 300);
};
</script>

<template>
  <NModal
    :show="props.show"
    preset="dialog"
    :min-width="600"
    :width="600"
    :title="$t('user-center.password-dialog.title')"
    :close-on-esc="true"
    :close-on-click-overlay="false"
    @update:show="handleClose"
  >
    >
    <NForm ref="passwordFormRef" :model="passwordForm" :rules="passwordRules" label-placement="left">
      <NFormItem label="旧密码" path="oldPassword">
        <NInput
          v-model:value="passwordForm.oldPassword"
          type="password"
          placeholder="请输入旧密码"
          show-password-on="mousedown"
        />
      </NFormItem>
      <NFormItem label="新密码" path="newPassword">
        <NInput
          v-model:value="passwordForm.newPassword"
          type="password"
          placeholder="请输入新密码"
          show-password-on="mousedown"
          class="password-input"
        />

        <div class="clear-fix"></div>

        <!-- 密码强度条 -->
        <div
          v-if="passwordForm.newPassword"
          class="password-strength"
          :class="{
            weak: getPasswordStrengthInfo.text === '弱',
            medium: getPasswordStrengthInfo.text === '中',
            strong: getPasswordStrengthInfo.text === '强'
          }"
        >
          <div
            class="strength-bar"
            :style="{
              background: `linear-gradient(90deg, ${getPasswordStrengthInfo.color} ${getPasswordStrengthInfo.width}, #f0f0f0 ${getPasswordStrengthInfo.width})`
            }"
          ></div>
          <NText class="strength-text" :class="[getPasswordStrengthInfo.level]" :depth="3">
            {{ getPasswordStrengthInfo.text }}
          </NText>
        </div>

        <!-- 密码提示 -->
        <div
          class="password-tips"
          :class="{
            'weak-tips': getPasswordStrengthInfo.text === '弱',
            'medium-tips': getPasswordStrengthInfo.text === '中',
            'strong-tips': getPasswordStrengthInfo.text === '强'
          }"
        >
          <NText text-type="secondary" depth="3" :size="12" :class="getPasswordStrengthInfo.text ? '' : 'secondary'">
            密码必须至少包含字母和数字，建议长度不少于8位，包含大小写字母和特殊字符以提高安全性
          </NText>
        </div>
      </NFormItem>
      <NFormItem label="确认新密码" path="confirmPassword">
        <NInput
          v-model:value="passwordForm.confirmPassword"
          type="password"
          placeholder="请再次输入新密码"
          show-password-on="mousedown"
        />
      </NFormItem>
    </NForm>
    <template #footer>
      <NButton @click="resetForm">重置</NButton>
      <NButton class="cancel-button" @click="handleClose">取消</NButton>
      <NButton type="primary" :loading="loading" class="confirm-button" @click="handleConfirm">确认修改</NButton>
    </template>
  </NModal>
</template>

<style scoped lang="scss">
// 密码强度样式
.password-strength {
  margin-top: 12px;
  display: block;
  clear: both;

  .strength-bar {
    height: 6px;
    width: 100%;
    background: rgba(0, 0, 0, 0.05);
    border-radius: 3px;
    overflow: hidden;
    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1);
    transition: background 0.3s ease;
    display: block;
  }

  .strength-text {
    font-size: 13px;
    margin-top: 6px;
    text-align: right;
    font-weight: 500;
    display: block;
    clear: both;
  }

  .strength-text.weak {
    color: #ff4d4f;
  }

  .strength-text.medium {
    color: #faad14;
  }

  .strength-text.strong {
    color: #52c41a;
  }

  &.weak .strength-bar {
    background: linear-gradient(
      90deg,
      #ff4d4f var(--strength-width, 33%),
      rgba(0, 0, 0, 0.05) var(--strength-width, 33%)
    );
  }

  &.medium .strength-bar {
    background: linear-gradient(
      90deg,
      #faad14 var(--strength-width, 66%),
      rgba(0, 0, 0, 0.05) var(--strength-width, 66%)
    );
  }

  &.strong .strength-bar {
    background: linear-gradient(
      90deg,
      #52c41a var(--strength-width, 100%),
      rgba(0, 0, 0, 0.05) var(--strength-width, 100%)
    );
  }
}

// 替代内联样式的CSS类
.password-input {
  display: block;
  width: 100%;
}

.clear-fix {
  clear: both;
}

.password-strength-section {
  display: block;
  clear: both;
  margin-top: 12px;
}

.password-hint-section {
  display: block;
  clear: both;
  margin-top: 10px;
}

.cancel-button,
.confirm-button {
  margin-left: 8px;
}

.strength-text {
  color: var(--strength-color);
}

// 密码提示样式
.password-tips {
  margin-top: 10px;
  font-size: 13px;
  line-height: 1.6;
  background: rgba(0, 0, 0, 0.05);
  padding: 12px;
  border-radius: 6px;
  border-left: 4px solid rgb(var(--primary-color));
  transition: all 0.3s ease;
  display: block;
  clear: both;
  color: rgba(0, 0, 0, 0.85);

  &.weak-tips {
    border-left-color: #ff4d4f;
    background: rgba(255, 77, 79, 0.1);
  }

  &.medium-tips {
    border-left-color: #faad14;
    background: rgba(250, 173, 20, 0.1);
  }

  &.strong-tips {
    border-left-color: #52c41a;
    background: rgba(82, 196, 26, 0.1);
  }

  & .secondary {
    color: rgba(0, 0, 0, 0.6);
  }
}

// 弹窗样式修复
.n-modal {
  &:deep(.n-modal__overlay) {
    background-color: rgba(0, 0, 0, 0.5) !important;
  }

  &:deep(.n-modal__content) {
    background-color: rgb(var(--container-bg-color));
    border-radius: 8px;
    box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);
  }
}

// 表单样式
.n-form-item {
  margin-bottom: 24px;

  &__label {
    font-weight: 500;
    color: rgba(0, 0, 0, 0.85);
    font-size: 14px;
  }
}

.n-input {
  border-radius: 6px;

  &:focus {
    border-color: #1890ff;
    box-shadow: 0 0 0 3px rgba(24, 144, 255, 0.15);
  }
}

// 响应式设计
@media (max-width: 768px) {
  .password-tips {
    font-size: 12px;
    padding: 10px;
  }

  .n-form-item {
    margin-bottom: 20px;
  }

  .password-strength .strength-text {
    font-size: 12px;
  }
}
</style>
